<?php
namespace Twoir\System\Support;

/**
 * 8个表处理方式 集合方法
 * 一个模型关联8张表， 正式表3张，待审核2张，存档表3张
 * cighsen02 qq 365182575
 * update: 2024.05.01
*/
trait ModelTrait
{
    //新增时id
    private static $lastid;
	/**
     * 字段默认值类型
     *
     * @return array
    */
    public static function fieldType()
    {
        $default = array_replace(static::MYDEFAULT['index'], static::MYDEFAULT['pri'], static::MYDEFAULT['sec']);

        array_walk($default, function(&$value, $key){

            $value = is_null($value) || 0 === $value ? 'int' : 'string';

        });

        return $default;
    }

    /**
	 * 表单名组确定
	*/
	private static function parseTable($type = '')
	{
	    $index 	= 'doc' === $type ? 'doc_index' : 'index';
		$pre	= in_array($type, ['doc', 'check']) ? $type . '_' : '';

		//8个表
		return [
		    'index' => static::MPREFIX . static::MODEL . static::TABLE[$index],
		    'pri'   => static::MPREFIX . static::MODEL . static::TABLE[$pre . 'pri'],
		    'sec'   => static::MPREFIX . static::MODEL . static::TABLE[$pre . 'sec'],
		];
	}

	/**
	 * 统计审核数量
	 *
	 * @param $type doc|check
	 * @return int
	*/
	public static function getCount($where = [], $field = '', $type = '')
    {
        global $empire, $dbtbpre;

        $str_where = static::parseWhere($where, false)['where'];

		$table = static::parseTable($type);
		//位置表位置
		$index = 'all' === $field ? 'index' : 'pri';

	 	$sql = sprintf("SELECT count(*) as total FROM %s%s", $dbtbpre . $table[$index], $str_where);

        return (int)$empire->gettotal($sql);
    }

    //统计待审核数
    public static function getCheckCount($where = [], $field = '')
    {
        return static::getCount($where, $field, 'check');
    }

    //存档
    public static function getDocCount($where = [], $field = '')
    {
        return static::getCount($where, $field, 'doc');
    }

	/**
	 * 拉取一条数据
	 * @param $where 键值数组 $field 值数组
	 *
	*/
	public static function getOne($where = [], $field = ['*'], $groupby = '', $orderby = '', $type = '')
	{
		$res = static::getList($where, $field, $groupby, $orderby, 1, 0, 0, $type);

	    return $res ? array_values($res)[0] : [];
	}

	//待审核
	public static function getCheckOne($where = [], $field = ['*'], $groupby = '', $orderby = '')
	{
	    $res = static::getList($where, $field, $groupby, $orderby, 1, 0, 0, 'check');

	    return $res ? array_values($res)[0] : [];
	}

	//存档
	public static function getDocOne($where = [], $field = ['*'], $groupby = '', $orderby = '')
	{
	    $res = static::getList($where, $field, $groupby, $orderby, 1, 0, 0, 'doc');

	    return $res ? array_values($res)[0] : [];
	}

	/**
	 * 读取多条(列表)
	 * @return array
	 */
	 public static function getList($where = [], $field = ['*'], $groupby = '', $orderby = '', $limit = 0, $pagesize = 10, $page = 0, $type = '')
	 {
	    global $empire, $dbtbpre, $emod_r, $etable_r;

	    $parse_where= static::parseWhere($where, false);
        $str_where  = $parse_where['where'];
        $data       = $parse_where['data'];
		//确定表位置正式表、待审核表、存档表
		$tables 	= static::parseTable($type);
		$get_field  = [];
		$mid 		= isset($etable_r[static::MODEL]['mid']) && $etable_r[static::MODEL]['mid'] ? $etable_r[static::MODEL]['mid'] : null;
		$savetxtf 	= $mid && isset($emod_r[$mid]['savetxtf']) && $emod_r[$mid]['savetxtf'] ? $emod_r[$mid]['savetxtf'] : null; //存文本字段
		$arr_where 	= [
			'index'		=> [],
			'pri'		=> [],
			'sec'		=> []
		];

		if (['*'] !== $field && count($data) > 0) {

			$where_field	= array_keys($data);
			$arr_where		= [
				'index'	=> array_filter(static::FIELD['index'], function($item) use ($where_field) {return in_array($item, $where_field);}),
				'pri'	=> array_filter(static::FIELD['pri'], function($item) use ($where_field) {return in_array($item, $where_field);}),
				'sec'	=> array_filter(static::FIELD['sec'], function($item) use ($where_field) {return in_array($item, $where_field);})
			];
		}

		$str_group	= null === $groupby || '' === $groupby ? '' : ' GROUP BY ' . $groupby;
		$str_order	= null === $orderby || '' === $orderby ? '' : ' ORDER BY ' . $orderby;
        $str_limit 	= 0 === $limit && 0 === $pagesize ? '' : ($limit > 0 ? ' LIMIT ' . $limit : ' LIMIT ' . ($page * $pagesize) . ',' . $pagesize);

        $option = [];
        $first  = true;
        foreach($tables as $t => $table) {

            $get_field  = ['*'] === $field ? static::FIELD[$t] : array_intersect(static::FIELD[$t], $field);
            $count      = count($get_field);

			if (['*'] === $field
				|| $count > 2
				|| (2 === $count && ((!in_array(static::PRIMARY, $get_field) && !in_array('classid', $get_field)) || 'pri' === $t))
				|| (1 === $count && (!(in_array(static::PRIMARY, $get_field) || in_array('classid', $get_field)) || 'pri' === $t)) ) {

				$option[$t] = [
					'field'     => $get_field,
					'table'     => $dbtbpre . $table,
					'where'     => $str_where,
					'group'		=> $str_group,
					'order'     => $str_order,
					'limit'     => $str_limit
				];
			}
        }

        //待返回数据
        $res = [];
        //主表
        if (isset($option['pri']) && !isset($option['sec'])) {

            $sql = sprintf("SELECT %s FROM %s%s%s%s%s",
				'`' . implode('`,`', $option['pri']['field']) . '`',
				$option['pri']['table'],
				$option['pri']['where'],
				$option['pri']['group'],
				$option['pri']['order'],
				$option['pri']['limit']
			);
        }

        //副表, 注意 分表不设置
        elseif (!isset($option['pri']) && isset($option['sec'])) {

            $sql = sprintf("SELECT %s FROM %s%s%s%s%s",
				'`' . implode('`,`', $option['sec']['field']) . '`',
				'' === $type ? $option['sec']['table'] . ('' === $type ? static::$stb : '') : $option['sec']['table'],
				$option['sec']['where'],
				$option['sec']['group'],
				$option['sec']['order'],
				$option['sec']['limit']
			);
        }

        //并表
        else{

			$sql = sprintf(
				'SELECT %s FROM `%s` AS a INNER JOIN `%s` AS b ON %s%s%s%s%s',
				'a.`' . implode('`,a.`', $option['pri']['field']) . '`' . ',b.`' . implode('`,b.`', array_diff($option['sec']['field'], ['classid', 'id'])) . '`',
				$option['pri']['table'],
				'' === $type ? $option['sec']['table'] . ('' === $type ? static::$stb : '') : $option['sec']['table'],
				'a.`' . static::PRIMARY . '` = b.`' . static::PRIMARY . '`',
				count($data) > 0 ? static::addPrefix($option['pri']['where']) : '',
				$option['pri']['group'] ? static::addPrefix($option['pri']['group']) : '',
				$option['pri']['order'] ? static::addPrefix($option['pri']['order']) : '',
				$option['pri']['limit']
			);
        }

		$sql = $empire->query($sql);

		if(0 < $num = $empire->num1($sql)){

		    while($r = $empire->fetch($sql)){

				//存文本处理
				if ($savetxtf && isset($r[$savetxtf])) $r[$savetxtf] = GetTxtFieldText($r[$savetxtf]);
				//去数字键
		        $res[] = array_filter($r, function($key){ return is_string($key);}, ARRAY_FILTER_USE_KEY);
		    }
		}

        return $res;
	 }

    /**
     * 插入数据
     *
	 * @param array $add
	 * @param string $type
     * @return int 0为失败，成功返回当前id
    */
	public static function insert($add = [], $type = '')
	{
		global $empire, $dbtbpre, $emod_r, $etable_r;

        //确定表位置
        $tables 	= static::parseTable($type);
		$mid 		= isset($etable_r[static::MODEL]['mid']) && $etable_r[static::MODEL]['mid'] ? $etable_r[static::MODEL]['mid'] : null;
		$savetxtf 	= $mid && isset($emod_r[$mid]['savetxtf']) && $emod_r[$mid]['savetxtf'] ? $emod_r[$mid]['savetxtf'] : null; //存文本字段

		//文本处理

        $insert 	= static::MYDEFAULT;
		array_walk($insert, function(&$value, $key) use($add) {

			//分组
			$value = array_filter($value, function($item) use ($key) {

			    return in_array($item, static::FIELD[$key]);

			}, ARRAY_FILTER_USE_KEY);

			$add = array_filter($add, function($item) use ($key) {

			    return in_array($item, static::FIELD[$key]);

			}, ARRAY_FILTER_USE_KEY);
			//更新
			$value 	= array_replace($value, $add);
		});

        //移除id, 自动增长
        if (is_null($add[static::PRIMARY])) unset($insert['index'][static::PRIMARY]);

        //副表位置
        if ($insert['pri']['stb'] > 0 && static::$stb !== $insert['pri']['stb']) static::$stb = $insert['pri']['stb'];

        //引索表插入
        $data       = static::parseInsert($insert['index']);
        $sql        = sprintf('INSERT INTO %s(%s) VALUES(%s)', $dbtbpre . $tables['index'], $data['key'], $data['value']);
        $sqlindex   = $empire->query($sql);

		$lastid = $empire->lastid();

		//主表
		$insert['pri'][static::PRIMARY] = $lastid;
		$data = static::parseInsert($insert['pri']);
		$sql = sprintf('INSERT INTO %s(%s) VALUES(%s)', $dbtbpre . $tables['pri'], $data['key'], $data['value']);
		$sqlpri = $empire->query($sql);

		//副表 parseInsert()
		$insert['sec'][static::PRIMARY] = $lastid;
		$data = static::parseInsert($insert['sec']);
		$sql = sprintf('INSERT INTO %s(%s) VALUES(%s)', $dbtbpre . $tables['sec'] . static::$stb, $data['key'], $data['value']);
		$sqlsec = $empire->query($sql);

        //更新失败
        if (!$sqlindex || !$sqlpri || !$sqlsec) $lastid = 0;

		return $lastid;
	}

	/**
     * @param array $where
	 * @param array $add
	 * @param int $limit
	 * @param string $type
	 * @return bool
     */
    public static function update($where = [], $add = [], $limit = null, $type = '')
    {
        global $empire, $dbtbpre, $emod_r, $etable_r;

         //去null值, 0值或负值不能去，
        $add = array_filter($add, function($item){ return null !== $item; });

        //找出要新字段进行更新
        $field = array_keys($add);

        $str_where = static::parseWhere($where, false)['where'];

        //确定表位置
        $tables 	= static::parseTable($type);
		$mid 		= isset($etable_r[static::MODEL]['mid']) && $etable_r[static::MODEL]['mid'] ? $etable_r[static::MODEL]['mid'] : null;
		$savetxtf 	= $mid && isset($emod_r[$mid]['savetxtf']) && $emod_r[$mid]['savetxtf'] ? $emod_r[$mid]['savetxtf'] : null; //存文本字段

		//初始值
		$sqlindex 	= $sqlpri = $sqlsec = false;

        //更新引索表
        $update = array_intersect(static::FIELD['index'], $field);
        if (!empty($update)) {

            $put_data   = array_filter($add, function($item) use ($update) { return in_array($item, $update); }, ARRAY_FILTER_USE_KEY);
            $sql        = sprintf('UPDATE %s SET %s%s%s', $dbtbpre . $tables['index'], static::parseUpdate($put_data), $str_where, $limit);
            $sqlindex     = $empire->query($sql);
        }

        //更新主表
        $update = array_intersect(static::FIELD['pri'], $field);
        if (!empty($update)) {

            $put_data   = array_filter($add, function($item) use ($update) { return in_array($item, $update); }, ARRAY_FILTER_USE_KEY);
            $sql        = sprintf('UPDATE %s SET %s%s%s', $dbtbpre . $tables['pri'], static::parseUpdate($put_data), $str_where, $limit);
            $sqlpri     = $empire->query($sql);
        }

        //更新副表
        $update = array_intersect(static::FIELD['sec'], $field);
        if (!empty($update)) {

            $put_data   = array_filter($add, function($item) use ($update) { return in_array($item, $update); }, ARRAY_FILTER_USE_KEY);
            $sql        = sprintf('UPDATE %s SET %s%s%s', $dbtbpre . $tables['sec'] . static::$stb, static::parseUpdate($put_data), $str_where, $limit);
            $sqlsec     = $empire->query($sql);
        }

        return $sqlindex || $sqlpri || $sqlsec;
    }

    /**
     * 删除数据
	 *
     * @param array $where
	 * @param int $limit
	 * @param string  $orderby
	 * @param string $type
	 * @return bool
    */
    public static function delete($where = [], $limit = null, $orderby = '', $type = '')
    {
        global $empire, $dbtbpre, $emod_r, $etable_r;

        $str_where = static::parseWhere($where, false)['where'];

		$table 		= static::parseTable($type);
		$mid 		= isset($etable_r[static::MODEL]['mid']) && $etable_r[static::MODEL]['mid'] ? $etable_r[static::MODEL]['mid'] : null;
		$savetxtf 	= $mid && isset($emod_r[$mid]['savetxtf']) && $emod_r[$mid]['savetxtf'] ? $emod_r[$mid]['savetxtf'] : null; //存文本字段

		$limit      = empty($limit) ? '' : ' LIMIT ' . $limit;
		$orderby    = null === $orderby || '' === $orderby ? '' : ' ORDER BY ' . $orderby;

		$index = sprintf('DELETE FROM %s %s%s%s', $dbtbpre . $table['index'], $str_where, $orderby, $limit);
		$index = $empire->query($sec);

		$pri = sprintf('DELETE FROM %s %s%s%s', $dbtbpre . $table['pri'], $str_where, $orderby, $limit);
		$pri = $empire->query($sec);

	 	$sec = sprintf('DELETE FROM %s %s%s%s', $dbtbpre . $table['sec'], $str_where, $orderby, $limit);
		$sec = $empire->query($sec);

        return $index && $pri && $sec;
    }

    /**
     * 原生语法 临时的 2024.04.20
     *
     * @param string $sql
     * @param string $type
     * @return array
    */
    public static function native($sql, $type = '')
    {
        global $empire, $dbtbpre;

        if ($sql && false !== strstr($sql, '[!db.pre!]')) {

            $sql = str_replace('[!db.pre!]', $dbtbpre, $sql);
        }

        // 返回数组类型
        if (false !== stristr($sql, 'GROUP BY') && false === stristr($sql, 'LIMIT ')) {

            $result = [];

            $sql = $empire->query($sql);

            if(0 < $num = $empire->num1($sql)){

                while($r = $empire->fetch($sql)){
                    //去数字键
                    $result[] = array_filter($r, function($key) { return is_string($key);}, ARRAY_FILTER_USE_KEY);
                }
            }

            return $result;
        }

        return $empire->fetch1($sql);
    }

    /**
	 * 联表名增加前缀
	 *
	 * @param string $str
	 * @return string
	 */
	private static function addPrefix($str)
	{
		foreach (static::FIELD['pri'] as $field) {

			if (false !== strstr($str, '`' . $field . '`')) $str = str_replace('`' . $field . '`', 'a.`' . $field . '`', $str);
		}

		foreach (static::FIELD['sec'] as $field) {

			if (!in_array($field, ['classid', static::PRIMARY]) && false !== strstr($str, '`' . $field . '`')) $str = str_replace('`' . $field . '`', 'b.`' . $field . '`', $str);
		}

		return $str;
	}
}
